//==============================================================================
#ifndef _GAMECLIENT_H_
#define _GAMECLIENT_H_

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#pragma once
#include "concurrent\Runnable.h"
#include "concurrent\ThreadPool.h"
#include "concurrent\Thread.h"
#include "concurrent\CriticalSection.h"
#include "ClientReceiver.h"
#include "ClientSender.h"
#include "..\Message.h"
#include "net\ClientSocket.h"
#include "net\ByteBuffer.h"
#include <iostream>
#include <sstream>
#include <string>
#include <queue>
#include <fstream>

using namespace std;
using namespace concurrent;
using namespace net;

class ClientSender;
class ClientReceiver;

typedef enum
{
	UNKNOWN_CLIENT_SESSION_TYPE,
	PLAYER_CLIENT_SESSION,
	OBSERVER_CLIENT_SESSION,
} CLIENT_SESSION_TYPE;

//==============================================================================
class GameClient : public Runnable
{
public:
	GameClient(string name, CLIENT_SESSION_TYPE type);
	GameClient(string name, CLIENT_SESSION_TYPE type, string port);
	GameClient(string name, CLIENT_SESSION_TYPE type, string host, string port);
    virtual ~GameClient(void);

	void setSocket(ClientSocket* socket);
	ClientSocket* getSocket();
	void setIsConnected(bool flag);
	bool isConnected(void);
	void setName(string name);
	string getName(void);
	void setIsReady(bool flag);
	bool isReady();
	void setIsConnectionError(bool flag);
	bool isConnectionError();
	string getTempPath();
	void setSceneBackgroundPath(string path);
	string getSceneBackgroundPath();
	void setSessionType(CLIENT_SESSION_TYPE type);
	CLIENT_SESSION_TYPE getSessionType();
	void setIsSessionAccepted(bool flag);
	bool isSessionAccepted();

	void sendNewSessionRequest(void);
	bool waitForStartGame(void);
	void setUpSession(void);
	void endSession(void);
    int startReceivingUpdates(void);
	int startSendingUpdates(void);
	void stopReceivingUpdates(void);
	void stopSendingUpdates(void);
	int disconnectFromServer(void);

	bool isInitialized(void);
	void queueUpdate(Message* message);
	bool hasUpdates(void);

	Message* unqueueUpdate(void);

	void setSender(ClientSender* sender);
	ClientSender* getSender(void);
	
	void setReceiver(ClientReceiver* receiver);
	ClientReceiver* getReceiver();

	CriticalSection* getInputQueueLock(void);
	CriticalSection* getOutputQueueLock(void);

	ByteBuffer* getSceneBuff();
	void receiveSceneState(void);

	queue<Message*>* getInputQueue(void);
	queue<Message*>* getOutputQueue(void);

	int start();
	void shutdown();
	void connectToServer(void);

protected:
	virtual DWORD run(void);

private:
	void receiveGameFiles(void);
	void getInfo(struct addrinfo*);

	string name;
	ByteBuffer* sceneBuff;
	ClientSocket* socket;
	bool _isReady;
	bool _isSessionAccepted;
	string sceneBackgroundPath;
	CLIENT_SESSION_TYPE sessionType;

	bool _isConnected;
	bool _isConnectionError;
	bool _isInitialized;
	bool _isSceneInitialized;

	Thread* senderThread;
	ClientSender* sender;

	Thread* receiverThread;
	ClientReceiver* receiver;

	queue<Message*> outputQueue;
	CriticalSection outputQueueLock;
	queue<Message*> inputQueue;
	CriticalSection inputQueueLock;

	static string DEFAULT_SERVER_HOST;
	static string DEFAULT_SERVER_PORT;
	static string TEMP_PATH;
};

#endif
